/**
 * This software was produced for the U. S. Government
 * under Contract No. FA8721-09-C-0002, and is
 * subject to the Rights in Noncommercial Computer Software
 * and Noncommercial Computer Software Documentation Clause
 * (DFARS) 252.227-7014 (JUN 1995)
 * 
 * (c) 2009 The MITRE Corporation. All Rights Reserved.
 *
 * SPMIF to OPNET Translator
 * Author: EWALTERS
 * Created: 2:21:25 PM, Aug 2, 2007
 * MITRE Corporation
 */
package com.mitre.spmif2opnet.analysis.ast;

import java.util.Collection;

import com.mitre.spmif2opnet.VisitorContext;
import com.mitre.spmif2opnet.analysis.AnalysisException;
import com.mitre.spmif2opnet.analysis.Identifier;
import com.mitre.spmif2opnet.analysis.SyncSymbol;
import com.mitre.spmif2opnet.spmif.PartnerTypeType;

/**
 * S-PMIF Node for synchronization primitives
 */
public class SynchroNode extends Node implements Visitee {
	/** 
	 * Pointer to the partner symbol
	 */
	private SyncSymbol      _partnerSym;
	/** 
	 * What S-PMIF partner type am I?
	 */
	private PartnerTypeType _myType;
	/** 
	 * What S-PMIF partner type is my parter?
	 */
	private PartnerTypeType _partnerType;
	/**
	 * Has the partner been translated?
	 */
	private boolean         _translated;
	
	/**
	 * Default constructor
	 * @param name  node name
	 * @param id    node id
	 * @param partner_sym partner symbol
	 * @param prob     node probability
	 * @param mytype   my partner type
	 * @param parttype my partner's partner type
	 */
	public SynchroNode(String name, Identifier id, SyncSymbol partner_sym, double prob, 
			PartnerTypeType mytype, PartnerTypeType parttype) {
		super(name, id.getNodeId(), prob);
		_partnerSym = partner_sym;
		_myType = mytype;
		_partnerType = parttype;
		_translated = false;
	}

	/**
	 * Visitor acceptor
	 */
	public <T> VisitorContext<T> accept(NodeVisitor<T> v, VisitorContext<T> c) {
		return v.visit(this, c);
	}
	
	/**
	 * Have we been translated?
	 * @return have we?
	 */
	public boolean isTranslated() {
		return _translated;
	}
	
	/**
	 * Yes we have been translated.
	 */
	public void setAsTranslated() {
		_translated = true;
	}

	/**
	 * Copy function - maintain the partnership
	 * @return the copy
	 */
	public SynchroNode copy() {
		Identifier id = new Identifier();
		id.setNodeId(Identifier.newNodeId(this.getId()));
		SynchroNode new_node 
			= new SynchroNode(this.getName(), id, _partnerSym, this.getProbability(), _myType, _partnerType);
		new_node._translated = this.isTranslated();
		new_node.copyResources(this);
		return new_node;
	}
	
	/**
	 * Is the synchronization asynchronous
	 * @return is it?
	 */
	public boolean isAsynchronous() {
		return _myType.equals(PartnerTypeType.ASYNCHRONOUS_CALL);
	}
	
	/**
	 * Partner accessor
	 * @return the partner scenario
	 */
	public Scenario getPartner() {
		return _partnerSym.getPartner();
	}
	
	/**
	 * What resources are associated with the node?
	 * @return the resource names
	 */
	public Collection<String> getResources() {
		Collection<String> res = super.getResources();
		if (res.isEmpty()) {
			try {
				Node sym_node = _partnerSym.getPartner().getStartGraph().getStartNode(); 
				res = sym_node.getResources();
			} catch (AnalysisException exc) {
				System.out.println("Unable to locate sync node resource for: " 
						+ this.toString() + " -> " + _partnerSym.toString());
			}
		}
		return res;
	}
	
	/**
	 * Get the services that correspond to the resource
	 * Use the resources of the partner node (if our not present)
	 * @param res_name the resource name
	 * @return the units
	 */
	public double getResourceService(String res_name) {
		Double service = null;
		try {
			Node sym_node = _partnerSym.getPartner().getStartGraph().getStartNode(); 
			if (_resources.isEmpty()) {
				service = new Double(sym_node.getResourceService(res_name));
			} else {
				service = _resources.get(res_name);
			}
		} catch (AnalysisException exc) {
			System.out.println("Unable to locate sync node resource service for: " 
					+ this.toString() + " -> " + _partnerSym.toString());
		}
		return (service == null) ? 0.0 : service.doubleValue();
	}

}
